import { useEffect, useState, forwardRef} from 'react';

import Select from '../Select';
import Input from '../Input';
import Row from '../Row';
import Button from '../Button';
import Header from '../Header';

import styles from './form.module.css'

const generateData = (schema, data) => {

  if (data === undefined) {
 
    const entries = Object.entries(schema)
    .map(([prop, {defaultValue=""}]) => [prop, defaultValue]);

    return Object.fromEntries(entries);
 
  } else {

    const entries = Object.entries(schema)
      .map(([prop, {defaultValue=""}]) => [prop, data[prop] ?? defaultValue]);
  
    return Object.fromEntries(entries);
  }

}

const Form = forwardRef(({schema, layout, data: initData, formType:directFormType, className, style}, ref) => {

  const {schema, layout, actions} = state;

  const [data, setData] = useState(generateData(schema, initData));

  const formType = (state.formType ?? directFormType) ?? 'normal';

  useEffect(() => {
    setData(generateData(schema, initData));
  }, [state, initData])

  const setPropVal = (prop, value) => {
    setData({...data, [prop]: value});
  }

  const formElems = [];
  const schemaElems = {};
  for (let [propName, entry] of Object.entries(schema)) {

    const value = data[propName];
    const onChange = (e) => {
      setPropVal(propName, e.target.value);
    }

    let fieldElem;
    switch (entry.type) {
      case 'list':
      case 'file':
      case 'select':
        const onSelectOption = (e) => {
          setPropVal(propName, e.target.value);
        }
        fieldElem = <Select {...{value, suggs: entry.suggs, onChange, onSelectOption, isDisabled: entry.isDisabled}}/>;
        break;
      case 'numeric':
      case 'password':
      case 'text':
      default:
        fieldElem = <Input {...{value, onChange, type:entry.type, isDisabled: entry.isDisabled}} />
    }

    let validElem = <div className={styles['msg']} />;
    for (let {validator, type, message} of entry.valids ?? []) {
      if (!validator(value)) {
        validElem = <div className={`${styles[`msg-${type}`]}`}>{message}</div>;
      }
    } 

    schemaElems[propName] = (<div key={propName} className={styles['form-control']}>
      <div className={styles['form-label']}>{entry.desc ?? propName}</div>
      {fieldElem}
      {validElem}
    </div>);
  }

  if (layout !== undefined) {
    for (let [index, prop] of layout.entries()) {
      if (typeof prop === 'string' && schemaElems[prop] !== undefined) {
        formElems.push(schemaElems[prop]);
      } else if (prop.row.length > 0) {
        const rowElems = prop.row
          .map(name => schemaElems[name])
          .filter(elem => elem !== undefined)
        formElems.push(<Row key={`row-${index}`}>{rowElems}</Row>);
      }
    }
  } else {
    for (let elem of Object.values(schemaElems)) {
      formElems.push(elem);
    }
  }

  let proceeds = [];

  if (transRules === undefined || Object.keys(transRules).length === 0) {
      
    proceeds.push(<Button key='ok-done' onClick={() => onTrans(data, 'END')}>OK</Button>)

  } else {

    const rules = Object.entries(transRules);

    if (rules.length === 1) {
      const [[newState, entry]] = rules;
      proceeds.push(<Button key='ok-trans' onClick={() => onTrans(data, newState, entry)}>{entry.desc ?? 'Proceed'}</Button>)
    } else {
      for (let i = 0; i < rules.length; i++ ) {

        const [name, entry] = rules[i];

        let style = entry.style
          ? entry.style
          : i === 0
          ? {type:'prim'}
          : {color:'base03', isOutlined: true};
        
        let text = entry.desc ?? name;

        proceeds.push(<Button key={`ok-trans-${name}`} onClick={() => onTrans(data, name, entry)} {...style}>{text}</Button>)
      }
      // a select for multi-state transitions;
    }
  }

  if (formType === 'normal') {

    formElems.push(<Row key='button-proc' style={{paddingTop: 10}}>{proceeds}</Row>);

    if (header !== undefined) {
      formElems.unshift(<Header  key={`header`} text={header} type='normal'/>);
    }

  } else if (formType === 'compact') {
    formElems.unshift(<Header key={`header`} text=' ' widgets={proceeds} type='compact'/>);
  }

  return <div {...{className, style, ref}}>
    {formElems}
  </div>
})

export default Form;